//! IndexerProgress to GenericProgress conversion

use super::state::{IndexPhase, IndexerProgress};
use crate::{
	domain::addressing::SdPath,
	infra::job::generic_progress::{GenericProgress, ToGenericProgress},
};
use std::path::PathBuf;

impl ToGenericProgress for IndexerProgress {
	fn to_generic_progress(&self) -> GenericProgress {
		let (percentage, completion_info, phase_name, phase_message) = match &self.phase {
			IndexPhase::Discovery { dirs_queued } => {
				// Discovery phase - 0-20% range
				let message = format!("Discovering files and directories ({} queued)", dirs_queued);
				// Start at very beginning for discovery
				let percentage = if *dirs_queued > 0 { 0.0 } else { 0.05 };
				(percentage, (0, 0), "Discovery".to_string(), message)
			}
			IndexPhase::Processing {
				batch,
				total_batches,
			} => {
				// Processing phase - show batch progress (20-60% of total)
				let batch_progress = if *total_batches > 0 {
					*batch as f32 / *total_batches as f32
				} else {
					0.0
				};
				// Map to 20-60% range
				let percentage = 0.2 + (batch_progress * 0.4);
				let message = format!("Processing entries (batch {}/{})", batch, total_batches);
				(
					percentage,
					(*batch as u64, *total_batches as u64),
					"Processing".to_string(),
					message,
				)
			}
			IndexPhase::ContentIdentification { current, total } => {
				// Content ID phase - show item progress (70-98% of total)
				let content_progress = if *total > 0 {
					(*current as f32 / *total as f32).min(1.0)
				} else {
					0.0
				};
				// Map to 70-98% range, never reach 100% in this phase
				let percentage = 0.7 + (content_progress * 0.28);
				let message = format!("Generating content identities ({}/{})", current, total);
				(
					percentage,
					(*current as u64, *total as u64),
					"Content Identification".to_string(),
					message,
				)
			}
			IndexPhase::Finalizing { processed, total } => {
				// Final phase - show actual progress of directory aggregation
				let finalizing_progress = if *total > 0 {
					(*processed as f32 / *total as f32).min(0.99) // Cap at 99% until truly complete
				} else {
					0.99
				};
				// Map to 99-100% range but reserve 100% for completion
				let percentage = 0.99 + (finalizing_progress * 0.01);
				let message = format!("Finalizing ({}/{})", processed, total);
				(
					percentage,
					(*processed as u64, *total as u64),
					"Finalizing".to_string(),
					message,
				)
			}
		};

		// Convert current_path string to SdPath only if it's a real filesystem path
		// During aggregation, current_path contains status messages like "Aggregating directory 3846/3877: info"
		// During other phases, it might contain actual file paths
		let current_path = if !self.current_path.is_empty()
			&& !self.current_path.starts_with("Aggregating directory")
			&& !self.current_path.starts_with("Finalizing")
		{
			// Only create SdPath if it looks like a real path (absolute or relative with separators)
			let path_buf = PathBuf::from(&self.current_path);
			if path_buf.is_absolute()
				|| self.current_path.contains('/')
				|| self.current_path.contains('\\')
			{
				// Try to parse as URI first (for cloud paths), fall back to local path
				SdPath::from_uri(&self.current_path)
					.ok()
					.or_else(|| Some(SdPath::local(path_buf)))
			} else {
				None
			}
		} else {
			None
		};

		// completion_info is already set correctly from phase matching above
		let final_completion = completion_info;

		// Create the generic progress
		let mut progress = GenericProgress::new(percentage, &phase_name, &phase_message)
			.with_bytes(self.total_found.bytes, self.total_found.bytes) // Total bytes found so far
			.with_performance(
				self.processing_rate,
				self.estimated_remaining,
				None, // Could calculate elapsed time from start
			)
			.with_errors(self.total_found.errors, 0) // No separate warning count in IndexerStats
			.with_metadata(self); // Include original indexer progress as metadata

		// Set completion data - for finalizing phase, manually set to avoid auto-percentage calculation
		match &self.phase {
			IndexPhase::Finalizing { .. } => {
				// Manually set completion to preserve our custom percentage calculation
				progress.completion.completed = final_completion.0;
				progress.completion.total = final_completion.1;
			}
			_ => {
				// For other phases, use normal with_completion which auto-calculates percentage
				progress = progress.with_completion(final_completion.0, final_completion.1);
			}
		}

		// Set current path if available
		if let Some(path) = current_path {
			progress = progress.with_current_path(path);
		}

		progress
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use crate::ops::indexing::state::{IndexPhase, IndexerStats};
	use std::time::Duration;

	#[test]
	fn test_discovery_phase_conversion() {
		let indexer_progress = IndexerProgress {
			phase: IndexPhase::Discovery { dirs_queued: 42 },
			current_path: "/home/user/documents".to_string(),
			total_found: IndexerStats::default(),
			processing_rate: 0.0,
			estimated_remaining: None,
			scope: None,
			persistence: None,
			is_ephemeral: false,
			action_context: None,
		};

		let generic = indexer_progress.to_generic_progress();
		assert_eq!(generic.phase, "Discovery");
		assert_eq!(generic.percentage, 0.0);
		assert!(generic.message.contains("42 queued"));
	}

	#[test]
	fn test_processing_phase_conversion() {
		let indexer_progress = IndexerProgress {
			phase: IndexPhase::Processing {
				batch: 3,
				total_batches: 10,
			},
			current_path: "/home/user/photos".to_string(),
			total_found: IndexerStats {
				files: 150,
				dirs: 20,
				bytes: 1024 * 1024 * 500, // 500MB
				symlinks: 5,
				skipped: 2,
				errors: 1,
			},
			processing_rate: 25.5,
			estimated_remaining: Some(Duration::from_secs(120)),
			scope: None,
			persistence: None,
			is_ephemeral: false,
			action_context: None,
		};

		let generic = indexer_progress.to_generic_progress();
		assert_eq!(generic.phase, "Processing");
		assert_eq!(generic.percentage, 0.3); // 3/10
		assert_eq!(generic.completion.completed, 3);
		assert_eq!(generic.completion.total, 10);
		assert_eq!(generic.performance.rate, 25.5);
		assert_eq!(
			generic.performance.estimated_remaining,
			Some(Duration::from_secs(120))
		);
		assert_eq!(generic.performance.error_count, 1);
	}

	#[test]
	fn test_content_identification_conversion() {
		let indexer_progress = IndexerProgress {
			phase: IndexPhase::ContentIdentification {
				current: 75,
				total: 100,
			},
			current_path: "/home/user/videos/movie.mp4".to_string(),
			total_found: IndexerStats::default(),
			processing_rate: 12.0,
			estimated_remaining: Some(Duration::from_secs(30)),
			scope: None,
			persistence: None,
			is_ephemeral: false,
			action_context: None,
		};

		let generic = indexer_progress.to_generic_progress();
		assert_eq!(generic.phase, "Content Identification");
		assert_eq!(generic.percentage, 0.75); // 75/100
		assert_eq!(generic.completion.completed, 75);
		assert_eq!(generic.completion.total, 100);
	}

	#[test]
	fn test_finalizing_phase_conversion() {
		let indexer_progress = IndexerProgress {
			phase: IndexPhase::Finalizing {
				processed: 95,
				total: 100,
			},
			current_path: "Aggregating directory data...".to_string(),
			total_found: IndexerStats::default(),
			processing_rate: 0.0,
			estimated_remaining: Some(Duration::from_secs(5)),
			scope: None,
			persistence: None,
			is_ephemeral: false,
			action_context: None,
		};

		let generic = indexer_progress.to_generic_progress();
		assert_eq!(generic.phase, "Finalizing");
		// With 95/100 progress: 0.99 + (0.95 * 0.01) = 0.9995
		assert!((generic.percentage - 0.9995).abs() < 0.0001);
		assert_eq!(generic.completion.completed, 95);
		assert_eq!(generic.completion.total, 100);
	}
}
